!======================================================================
!
!    HEEDS (Higher Education Enrollment Decision Support) - A program
!      to create enrollment scenarios for 'next term' in a university
!    Copyright (C) 2012, 2013 Ricolindo L Carino
!
!    This file is part of the HEEDS program.
!
!    HEEDS is free software: you can redistribute it and/or modify
!    it under the terms of the GNU General Public License as published by
!    the Free Software Foundation, either version 3 of the License, or
!    (at your option) any later version.
!
!    HEEDS is distributed in the hope that it will be useful,
!    but WITHOUT ANY WARRANTY; without even the implied warranty of
!    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
!    GNU General Public License for more details.
!
!    You should have received a copy of the GNU General Public License
!    along with this program (see the file COPYING.TXT). If not, see
!    <http://www.gnu.org/licenses/>.
!
!    Send inquiries about HEEDS to:
!      Ricolindo L Carino
!      E-mail: Ricolindo.Carino@AcademicForecasts.com
!      Address: 600 Cruise St., Starkville, MS 39759, U.S.A.
!
!======================================================================


module TEACHERS

    use DEPARTMENTS

    implicit none

    ! faculty variables
    integer, parameter :: &
        MAX_ALL_TEACHERS = 2000, & ! maximum number of eachers
        MAX_LEN_TEACHER_CODE=20, & ! length of login name
        MAX_LEN_TEACHER_NAME=40, & ! length of Teacher name
        MAX_LEN_TEACHER_DEGREE=40, & ! length of string for Teacher degrees
        MAX_LEN_ACADEMIC_RANK=19, & ! length of string for academic rank
        MAX_LEN_STEP_IN_RANK=6 ! length of string for step in academic rank

    type :: TYPE_TEACHER
        character (len=MAX_LEN_TEACHER_CODE) :: TeacherId
        character (len=MAX_LEN_TEACHER_NAME) :: Name
        integer :: DeptIdx, MaxLoad, Rank, Step
        character (len=MAX_LEN_TEACHER_DEGREE) :: Bachelor, Master, Doctorate, Specialization
    end type TYPE_TEACHER

    integer :: NumTeachers, NumAdditionalTeachers

    type (TYPE_TEACHER), dimension(0:MAX_ALL_TEACHERS) :: Teacher
    integer, dimension(0:MAX_ALL_TEACHERS) :: TeacherRank

    character (len=MAX_LEN_ACADEMIC_RANK), dimension(0:4) :: AcademicRank = (/ &
        '(Specify Rank)     ', &
        'Instructor         ', &
        'Assistant Professor', &
        'Associate Professor', &
        'Professor          ' /)

    character (len=MAX_LEN_STEP_IN_RANK), dimension(0:12) :: RankStep = (/ &
        '(Step)', &
        'I     ', &
        'II    ', &
        'III   ', &
        'IV    ', &
        'V     ', &
        'VI    ', &
        'VII   ', &
        'VIII  ', &
        'IX    ', &
        'X     ', &
        'XI    ', &
        'XII   ' /)

    ! private tokens
    character (len=MAX_LEN_FILE_PATH), private :: fileName
    character (len=MAX_LEN_XML_LINE), private :: line
    integer, private :: unitNum=2, eof, ndels, pos(30)

contains

#include "custom_read_teachers.F90"

    subroutine read_teachers(path, errNo)

        character(len=*), intent(in) :: path
        integer, intent (out) :: errNo

        logical :: noXML

        NumTeachers = 0
        NumAdditionalTeachers = 0

        call initialize_teacher(Teacher(0))
        Teacher = Teacher(0)
        Teacher(0)%TeacherId = 'TBA'
        Teacher(0)%Name = '(Teacher to be assigned)'

        noXML = .false.
        call xml_read_teachers(path, errNo) ! try the XML file
        if (errNo/=0) then ! something wrong with XML file
            noXML = .true.
            call custom_read_teachers(path, errNo) ! try custom format
            if (errNo/=0) return ! something still wrong
        end if

        call sort_alphabetical_teachers()

        ! additional teacher info
        call xml_read_teachers_other(path, errNo)

        ! write the XML TEACHERS file?
        if (noXML .and. NumTeachers>0) call xml_write_teachers(path)

        return
    end subroutine read_teachers



    subroutine initialize_teacher (wrkTeacher, tCode, tName, iDept, iLoad, iRank, iStep, &
            tBachelor, tMaster, tDoctorate, tSpecialization)

        type(TYPE_TEACHER), intent (out) :: wrkTeacher
        character(len=*), intent (in), optional :: tCode, tName
        integer, intent (in), optional :: iDept, iLoad, iRank, iStep
        character(len=*), intent (in), optional :: tBachelor, tMaster, tDoctorate, tSpecialization

        if (present(tCode)) then
            wrkTeacher = TYPE_TEACHER(tCode, tName, iDept, iLoad, iRank, iStep, &
                tBachelor, tMaster, tDoctorate, tSpecialization)

        else ! place teacher under REGISTRAR
            wrkTeacher = TYPE_TEACHER(SPACE, SPACE, NumDepartments, 12, 0, 0, SPACE, SPACE, SPACE, SPACE)

        end if

        return
    end subroutine initialize_teacher


    function index_to_teacher (token)

        integer :: index_to_teacher
        character (len=MAX_LEN_TEACHER_CODE), intent (in) :: token

        integer :: i, j, tdx

        tdx = 0
        if (token==Teacher(tdx)%TeacherId) then
            index_to_teacher = tdx
            return
        end if

        ! try the newly added Teachers
        do tdx=NumTeachers+1,NumTeachers+NumAdditionalTeachers
            if (token==Teacher(tdx)%TeacherId) then
                index_to_teacher = tdx
                return
            end if
        end do

        ! try the original teachers
        i = 1
        j = NumTeachers
        do
            if (i>j) then
                tdx = 0
                exit
            else
                tdx = (i + j)/2
                if (token==Teacher(tdx)%TeacherId) then
                    exit
                else if (token<Teacher(tdx)%TeacherId) then
                    j = tdx-1
                else
                    i = tdx+1
                end if
            end if
        end do
        index_to_teacher = tdx

        return
    end function index_to_teacher


    subroutine sort_teachers

        integer :: i, j
        type(TYPE_TEACHER) :: wrkTeacher

        do i=1,NumTeachers-1
            do j=i+1,NumTeachers
                if (Teacher(i)%TeacherId>Teacher(j)%TeacherId) then
                    wrkTeacher = Teacher(i)
                    Teacher(i) = Teacher(j)
                    Teacher(j) = wrkTeacher
                end if
            end do
        end do

        return
    end subroutine sort_teachers


    subroutine sort_alphabetical_teachers()

        integer :: i, j, k
        !write (*,*) 'Sorting teachers alphabetically... please wait...'

        TeacherRank = 0
        do i=1,NumTeachers
            TeacherRank(i) = i
        end do

        do i=1,NumTeachers-1

            do j=i+1,NumTeachers
                if (Teacher(TeacherRank(i))%Name > Teacher(TeacherRank(j))%Name) then
                    k = TeacherRank(i)
                    TeacherRank(i) = TeacherRank(j)
                    TeacherRank(j) = k
                end if
            end do

        end do

        return
    end subroutine sort_alphabetical_teachers


    subroutine xml_write_teachers(path)

        character(len=*), intent(in) :: path
        integer :: ldx

        ! training only?
        if (noWrites) return

        ! basic info
        fileName = trim(dirXML)//trim(path)//'TEACHERS.XML'
        call xml_open_file(unitNum, XML_ROOT_TEACHERS, fileName, ldx)

        write(unitNum,AFORMAT) &
        '    <comment>', &
        '        Generated by '//PROGNAME//VERSION//' on '//currentDate(1:4)// &
                    FSLASH//currentDate(5:6)//FSLASH//currentDate(7:8), &
        '        TeacherId - teacher code', &
        '        Name - name of teacher', &
        '        Department - responsible department', &
        '    </comment>'

        do ldx = 1,NumTeachers+NumAdditionalTeachers

            call xml_write_character(unitNum, indent0, 'Teacher')
            call xml_write_character(unitNum, indent1, 'TeacherId', Teacher(ldx)%TeacherId)
            call xml_write_character(unitNum, indent1, 'Name', Teacher(ldx)%Name)
            call xml_write_character(unitNum, indent1, 'Department', Department(Teacher(ldx)%DeptIdx)%Code)
            call xml_write_character(unitNum, indent0, '/Teacher')

        end do

        call xml_close_file(unitNum, XML_ROOT_TEACHERS)

        ! additional info
        fileName = trim(dirXML)//trim(path)//'TEACHERS-OTHER.XML'
        call xml_open_file(unitNum, XML_ROOT_TEACHERS, fileName, ldx)

        write(unitNum,AFORMAT) &
        '    <comment>', &
        '        Generated by '//PROGNAME//VERSION//' on '//currentDate(1:4)// &
                    FSLASH//currentDate(5:6)//FSLASH//currentDate(7:8), &
        '        TeacherId - teacher code', &
        '        MaxLoad - maximum teaching load', &
        '        Rank - academic rank', &
        '        Step - step in academic rank', &
        '        Bachelor - BSc degree', &
        '        Master - MSc degree', &
        '        Doctorate - PhD degree', &
        '        Specialization - Area of specialization', &
        '    </comment>'

        do ldx = 1,NumTeachers+NumAdditionalTeachers

            call xml_write_character(unitNum, indent0, 'Teacher')
            call xml_write_character(unitNum, indent1, 'TeacherId', Teacher(ldx)%TeacherId)
            call xml_write_integer(unitNum, indent1, 'MaxLoad', Teacher(ldx)%MaxLoad)
            if (Teacher(ldx)%Rank>0) &
                call xml_write_character(unitNum, indent1, 'Rank', AcademicRank(Teacher(ldx)%Rank))
            if (Teacher(ldx)%Step>0) &
                call xml_write_character(unitNum, indent1, 'Step', RankStep(Teacher(ldx)%Step))
            if (Teacher(ldx)%Bachelor/=SPACE) &
                call xml_write_character(unitNum, indent1, 'Bachelor', Teacher(ldx)%Bachelor)
            if (Teacher(ldx)%Master/=SPACE) &
                call xml_write_character(unitNum, indent1, 'Master', Teacher(ldx)%Master)
            if (Teacher(ldx)%Doctorate/=SPACE)  &
                call xml_write_character(unitNum, indent1, 'Doctorate', Teacher(ldx)%Doctorate)
            if (Teacher(ldx)%Specialization/=SPACE)  &
                call xml_write_character(unitNum, indent1, 'Specialization', Teacher(ldx)%Specialization)
            call xml_write_character(unitNum, indent0, '/Teacher')

        end do

        call xml_close_file(unitNum, XML_ROOT_TEACHERS)

        return
    end subroutine xml_write_teachers


    subroutine xml_read_teachers(path, errNo)

        character(len=*), intent(in) :: path
        integer, intent (out) :: errNo

        integer :: i, j
        character(len=MAX_LEN_XML_LINE) :: value
        character(len=MAX_LEN_XML_TAG) :: tag
        type(TYPE_TEACHER) :: wrkTeacher
        character (len=MAX_LEN_DEPARTMENT_CODE) :: tDept
        character (len=MAX_LEN_STEP_IN_RANK) :: tStep
        character (len=MAX_LEN_ACADEMIC_RANK) :: tRank

        ! open file, return on any error
        fileName = trim(dirXML)//trim(path)//'TEACHERS.XML'
        call xml_open_file(unitNum, XML_ROOT_TEACHERS, fileName, errNo, forReading)
        if (errNo/=0) return

        ! examine the file line by line
        do

            read(unitNum, AFORMAT, iostat=eof) line
            if (eof<0) exit

            ! get tag and value if any; exit on any error
            call xml_parse_line(line, tag, value, eof)
            if (eof/=0) exit

            select case (trim(tag))

                case ('Teacher') ! initialize temporary teacher data
                    call initialize_teacher(wrkTeacher)

                case ('TeacherId')
                    call upper_case(value)
                    wrkTeacher%TeacherId = adjustl(value)

                case ('Name')
                    call upper_case(value)
                    wrkTeacher%Name = adjustl(value)

                case ('Department')
                    tDept = adjustl(value)
                    j = index_to_dept(tDept)
                    if (j==0) j = NumDepartments ! use REGISTRAR for invalid department code
                    wrkTeacher%DeptIdx = j

                ! read additional info here in case file has the old format
                case ('MaxLoad')
                    wrkTeacher%MaxLoad = atoi(value)

                case ('Rank')
                    tRank = adjustl(value)
                    j = 0
                    do i=1,4
                        if (tRank/=AcademicRank(i)) cycle
                        j = i
                        exit
                    end do
                    wrkTeacher%Rank = j

                case ('Step')
                    tStep = adjustl(value)
                    j = 0
                    do i=1,12
                        if (tStep/=RankStep(i)) cycle
                        j = i
                        exit
                    end do
                    wrkTeacher%Step = j

                case ('Bachelor')
                    wrkTeacher%Bachelor = adjustl(value)

                case ('Master')
                    wrkTeacher%Master = adjustl(value)

                case ('Doctorate')
                    wrkTeacher%Doctorate = adjustl(value)

                case ('Specialization')
                    wrkTeacher%Specialization = adjustl(value)

                case ('/Teacher') ! add/merge temporary teacher data to Teacher()
                    ! teacher encountered previously?
                    i = 0
                    do j=1,NumTeachers
                        if (wrkTeacher%TeacherId/=Teacher(j)%TeacherId) cycle
                        i = j
                        exit
                    end do
                    if (i/=0) then ! overwrite existing record
                        call file_log_message ('Duplicate record for '//trim(wrkTeacher%TeacherId)//'; updated.')
                        Teacher(i) = wrkTeacher
                    else
                        NumTeachers = NumTeachers + 1
                        call check_array_bound (NumTeachers, MAX_ALL_TEACHERS, 'MAX_ALL_TEACHERS')
                        Teacher(NumTeachers) = wrkTeacher
                        Department(wrkTeacher%DeptIdx)%hasInfo = .true.
                    end if

                case default
                    ! do nothing
            end select

        end do

        call xml_close_file(unitNum)

        call sort_teachers()

        return
    end subroutine xml_read_teachers


    subroutine xml_read_teachers_other(path, errNo)

        character(len=*), intent(in) :: path
        integer, intent (out) :: errNo

        integer :: i, j
        character(len=MAX_LEN_XML_LINE) :: value
        character(len=MAX_LEN_XML_TAG) :: tag
        type(TYPE_TEACHER) :: wrkTeacher
        character (len=MAX_LEN_STEP_IN_RANK) :: tStep
        character (len=MAX_LEN_ACADEMIC_RANK) :: tRank

        ! open file, return on any error
        errNo = 0
        fileName = trim(dirXML)//trim(path)//'TEACHERS-OTHER.XML'
        call xml_open_file(unitNum, XML_ROOT_TEACHERS, fileName, eof, forReading)
        if (eof/=0) return

        ! examine the file line by line
        do

            read(unitNum, AFORMAT, iostat=eof) line
            if (eof<0) exit

            ! get tag and value if any; exit on any error
            call xml_parse_line(line, tag, value, eof)
            if (eof/=0) exit

            select case (trim(tag))

                case ('Teacher')
                    ! ignore

                case ('TeacherId') ! copy teacher data
                    call upper_case(value)
                    wrkTeacher%TeacherId = adjustl(value)
                    j = index_to_teacher(wrkTeacher%TeacherId)
                    wrkTeacher = Teacher(j)

                case ('MaxLoad')
                    wrkTeacher%MaxLoad = atoi(value)

                case ('Rank')
                    tRank = adjustl(value)
                    j = 0
                    do i=1,4
                        if (tRank/=AcademicRank(i)) cycle
                        j = i
                        exit
                    end do
                    wrkTeacher%Rank = j

                case ('Step')
                    tStep = adjustl(value)
                    j = 0
                    do i=1,12
                        if (tStep/=RankStep(i)) cycle
                        j = i
                        exit
                    end do
                    wrkTeacher%Step = j

                case ('Bachelor')
                    wrkTeacher%Bachelor = adjustl(value)

                case ('Master')
                    wrkTeacher%Master = adjustl(value)

                case ('Doctorate')
                    wrkTeacher%Doctorate = adjustl(value)

                case ('Specialization')
                    wrkTeacher%Specialization = adjustl(value)

                case ('/Teacher') ! update  Teacher() with temporary teacher data
                    j = index_to_teacher(wrkTeacher%TeacherId)
                    Teacher(j) = wrkTeacher

                case default
                    ! do nothing
            end select

        end do

        call xml_close_file(unitNum)

        return
    end subroutine xml_read_teachers_other


end module TEACHERS
